package core;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import net.Daemon;

import util.Debug;

public class Main extends JFrame {

	/**
	 * Generated UID
	 */
	private static final long serialVersionUID = -6069462403474851173L;

	private static final int SLEEP_MS = 50;
	private static final String DEFAULT_TITLE = "P2P node";
	private boolean isServent = false;
	private Servent myServent;
	private JPanel rootPanel;
	private JTextArea log;

	private JTextField myPORT;
	private JButton startStop;
	
	private JLabel ipExplain;
	private JTextField entryIP;
	private JLabel portExplain;
	private JTextField entryPORT;
	private JButton connect;
	
	/** A text field for messages that should be sent to other nodes. */
	private JLabel messageExplain;
	private JTextField messageField;
	private JButton postMsg;
	private JButton notifyButton;
	
	private JLabel searchExplain;
	private JTextField searchField;
	private JButton searchButton;

	private JLabel connectionsExplain;
	private JComboBox connections;
	private JButton disconnect;

	public Main() {
		super(DEFAULT_TITLE);

		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setVisible(true);
		rootPanel = new JPanel();
		JPanel actionsPanel = new JPanel();
		actionsPanel.setLayout(new BoxLayout(actionsPanel, BoxLayout.Y_AXIS));
		log = new JTextArea(30, 30);
		JScrollPane logPane = new JScrollPane(log);
		
		JLabel myPortExplain = new JLabel("Enter Daemon port for this node");
		myPORT = new JTextField(""+Daemon.DEFAULT_PORT);
		
		// Button to start and stop the servent thread
		startStop = new JButton("Start");
		
		ipExplain = new JLabel("Enter IP adress to connect to");
		ipExplain.setEnabled(false);
		entryIP = new JTextField("localhost");
		entryIP.setEnabled(false);
		portExplain = new JLabel("Enter Daemon port of remote node");
		portExplain.setEnabled(false);
		entryPORT = new JTextField(""+Daemon.DEFAULT_PORT);
		entryPORT.setEnabled(false);
		connect = new JButton("Connect");
		connect.setEnabled(false);
		
		// Action listener for connect button
		connect.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				String ip = entryIP.getText();
				int port = Integer.parseInt(entryPORT.getText());
				String host = ip+":"+port;
				boolean unique = myServent.unique(host);
				if(unique) {
					host = myServent.connectTo(ip, port);
					// TODO: rollback if connection failed
				}
				if(unique) {
					connections.addItem(host);
				}
			}
		});
		
		connectionsExplain = new JLabel("List of active connections:");
		connectionsExplain.setEnabled(false);
		connections = new JComboBox();
		connections.setEnabled(false);
		disconnect = new JButton("Disconnect");
		disconnect.setEnabled(false);

		// Action listener for disconnect button
		disconnect.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int index = connections.getSelectedIndex();
				if(index != -1) {
					String host = (String) connections.getItemAt(index);
					connections.removeItemAt(index);
					String[] adress = host.split(":");
					String ip = adress[0];
					int port = Integer.parseInt(adress[1]);
					myServent.disconnectFrom(ip, port);
				}
			}
		});
		
		messageExplain = new JLabel("Message");
		messageExplain.setEnabled(false);
		messageField = new JTextField("");
		messageField.setEditable(true);
		messageField.setEnabled(false);
		postMsg = new JButton("Post message");
		postMsg.setEnabled(false);
		
		// Action listener for post message button
		postMsg.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				myServent.postMessage(messageField.getText());
			}
		});
		
		notifyButton = new JButton("Notify");
		notifyButton.setEnabled(false);
		
		// Action listener for notify button
		notifyButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				myServent.notify(null);
			}
		});
		
		searchExplain = new JLabel("Search");
		searchExplain.setEnabled(false);
		searchField = new JTextField("localhost:"+Daemon.DEFAULT_PORT);
		searchField.setEditable(true);
		searchField.setEnabled(false);
		searchButton = new JButton("Search");
		searchButton.setEnabled(false);
		
		// Action listener for search button
		searchButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				myServent.search(searchField.getText());
			}
		});
		
		// Add rootPanel to frame, place logPane and actionsPanel in rootPanel
		add(rootPanel);
		rootPanel.add(logPane);
		rootPanel.add(actionsPanel);

		// Add items to actionsPanel
		actionsPanel.add(myPortExplain);
		actionsPanel.add(myPORT);
		actionsPanel.add(startStop);
		actionsPanel.add(ipExplain);
		actionsPanel.add(entryIP);
		actionsPanel.add(portExplain);
		actionsPanel.add(entryPORT);
		actionsPanel.add(connect);
		actionsPanel.add(connectionsExplain);
		actionsPanel.add(connections);
		actionsPanel.add(disconnect);
		actionsPanel.add(messageExplain);
		actionsPanel.add(messageField);
		actionsPanel.add(postMsg);
		actionsPanel.add(notifyButton);
		actionsPanel.add(searchExplain);
		actionsPanel.add(searchField);
		actionsPanel.add(searchButton);

		// Final modifications to frame
		setResizable(false);
		this.setLocation(10, 10);
		pack();
	}

	public void run() {
		while (true) {
			pack();
			try {
				Thread.sleep(SLEEP_MS);
			} catch (InterruptedException e) {
				if(Debug.verbose) {
					e.printStackTrace();
				}
			}
		}
	}

	public synchronized void writeToLog(String name, String msg) {
		log.insert(name + ": " + msg + "\n", 0);
		log.setCaretPosition(0); // MIND = BLOWN
	}

	/**
	 * Create a Frame and set everything. Would like to have all the setting in
	 * a constructor but its hard to fix the action listener.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		final Main foo = new Main();

		foo.startStop.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!foo.isServent()) {
//					switch (foo.whoami.getSelectedIndex()) {
					int port = Integer.parseInt(foo.myPORT.getText());
					foo.myServent = new Servent(port, ""+port, foo);
					foo.setTitle(""+port);
					foo.isServent(true);
					foo.startStop.setText("Stop");
					foo.myServent.start();
					foo.myServent.setRunning(true);
					foo.ipExplain.setEnabled(true);
					foo.entryIP.setEnabled(true);
					foo.portExplain.setEnabled(true);
					foo.entryPORT.setEnabled(true);
					foo.connect.setEnabled(true);
					foo.connections.setEnabled(true);
					foo.disconnect.setEnabled(true);
					foo.connectionsExplain.setEnabled(true);
					foo.messageExplain.setEnabled(true);
					foo.messageField.setEnabled(true);
					foo.postMsg.setEnabled(true);
					foo.notifyButton.setEnabled(true);
					foo.searchExplain.setEnabled(true);
					foo.searchField.setEnabled(true);
					foo.searchButton.setEnabled(true);
				} else {
					foo.stop();
					foo.setTitle(DEFAULT_TITLE);
				}

			}
		});

		foo.run();
	}

	public void stop() {
		myServent.setRunning(false);
		isServent(false);
		startStop.setText("Start");
		ipExplain.setEnabled(false);
		entryIP.setEnabled(false);
		portExplain.setEnabled(false);
		entryPORT.setEnabled(false);
		connect.setEnabled(false);
		connectionsExplain.setEnabled(false);
		connections.setEnabled(false);
		disconnect.setEnabled(false);
		messageExplain.setEnabled(false);
		messageField.setEnabled(false);
		postMsg.setEnabled(false);
		notifyButton.setEnabled(false);
		searchExplain.setEnabled(false);
		searchField.setEnabled(false);
		searchButton.setEnabled(false);
	}

	private synchronized void isServent(boolean isServent) {
		this.isServent = isServent;
	}

	private synchronized boolean isServent() {
		return isServent;
	}

}
